﻿using System;
using System.Net.Sockets;
using System.Text;

namespace ManageSieveClient
{
    public class ManageSieveClient
    {
        private readonly TcpClient _tcpClient = new TcpClient();
        private NetworkStream _stream;

        private string GetResponse()
        {
            var readBuffer = new byte[1024];
            var asyncReader = _stream.BeginRead(readBuffer, 0, readBuffer.Length, null, null);
            var handle = asyncReader.AsyncWaitHandle;

            var completed = handle.WaitOne(2000, false);
            if (completed)
            {
                var bytesRead = _stream.EndRead(asyncReader);

                var message = new StringBuilder();
                message.Append(Encoding.ASCII.GetString(readBuffer, 0, bytesRead));

                return message.ToString();
            }

            return "";
        }

        public void Connect(string host, int port)
        {
            _tcpClient.Connect(host, port);
            _stream = _tcpClient.GetStream();
            var result = GetResponse();
            if (!result.Contains("OK"))
                throw new Exception(result);
        }

        public void Authenticate(string username, string password)
        {
            var sasl = Convert.ToBase64String(Encoding.UTF8.GetBytes(username + '\0' + username + '\0' + password));
            var command = "Authenticate \"PLAIN\" \"" + sasl + "\"\n";
            var data = Encoding.UTF8.GetBytes(command);
            _stream.Write(data, 0, data.Length);
            var result = GetResponse();
            if (!result.Contains("OK"))
                throw new Exception(result);
        }

        public void PutScript(string scriptName, string scriptContent)
        {
            var command = "Putscript \"" + scriptName + "\" {" + scriptContent.Length + "}\n" + scriptContent + "\n";
            var data = Encoding.UTF8.GetBytes(command);
            _stream.Write(data, 0, data.Length);
            var result = GetResponse();
            if (!result.Contains("OK"))
                throw new Exception(result);
        }

        public void SetActive(string scriptName)
        {
            var command = "Setactive \"" + scriptName + "\"\n";
            var data = Encoding.UTF8.GetBytes(command);
            _stream.Write(data, 0, data.Length);
            var result = GetResponse();
            if (!result.Contains("OK"))
                throw new Exception(result);
        }

        public void Logout()
        {
            var command = "Logout\n";
            var data = Encoding.UTF8.GetBytes(command);
            _stream.Write(data, 0, data.Length);
            var result = GetResponse();
            if (!result.Contains("OK"))
                throw new Exception(result);
        }

        public void Close()
        {
            _stream.Close();
            _tcpClient.Close();
        }
    }
}
